﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.UI.WebControls;

using umbraco.cms.businesslogic.datatype;
using umbraco.cms.businesslogic.media;
using umbraco.interfaces;
using System.Web.UI;
using System.Collections;
using umbraco.uicontrols.TreePicker;
using DigibizTree;
using umbraco.IO;

namespace DigibizAdvancedMediaPicker
{
    public class DAMP_PrevalueEditor : PlaceHolder, IDataPrevalue
    {
        /// <summary>
        /// The underlying base data-type.
        /// </summary>
        private readonly BaseDataType _dataType;

        private SortedList _preValues = null;

        /// <summary>
        /// An object to temporarily lock writing to the database.
        /// </summary>
        private static readonly object m_Locker = new object();

        #region Store

        /// <summary>
        /// Gets or sets the save options.
        /// </summary>
        /// <value></value>
        protected DropDownList DropDownListSave
        { 
            get; set; 
        }

        #endregion

        #region Start node

        /// <summary>
        /// Gets or sets how the start node will be chosen.
        /// </summary>
        protected RadioButtonList RadioSelectStartNode
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets MultiView StartNode.
        /// </summary>
        protected MultiView MultiViewStartNode
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the view with the media picker.
        /// </summary>
        protected View ViewMediaPickerStartNode
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the view with the XPath.
        /// </summary>
        protected View ViewXpathStartNode
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the allowed start node.
        /// </summary>
        protected SimpleMediaPicker SimpleMediaPickerStartNode
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the XPath textbox.
        /// </summary>
        protected TextBox TxtStartNodeXpath
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the checkbox if the start node can be ignored for the admin.
        /// </summary>
        protected CheckBox CheckBoxIgnoreStartNodeAdmin
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the picker start text.
        /// </summary>
        protected Literal LitPickerStart
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the picker end text.
        /// </summary>
        protected Literal LitPickerEnd
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the XPath start text.
        /// </summary>
        protected Literal LitXpathStart
        {
            get;
            set;
        }

        /// <summary>
        /// /// Gets or sets the XPath end text.
        /// </summary>
        protected Literal LitXpathEnd
        {
            get;
            set;
        }

        #endregion

        #region Allowed Extensions

        /// <summary>
        /// Gets or sets the allowed extensions.
        /// </summary>
        protected TextBox TxtAllowedExtensions
        {
            get;
            set;
        }

        #endregion

        #region Allow Create

        /// <summary>
        /// Gets or sets option to allow Creating new media
        /// </summary>
        protected CheckBox CheckBoxHideCreate
        {
            get;
            set;
        }

        #endregion

        #region Media Types

        /// <summary>
        /// Gets or sets the allowed selectable Media Types
        /// </summary>
        protected CheckBoxList CheckBoxListSelectableMediaTypes
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the allowed create-able Media Types
        /// </summary>
        protected CheckBoxList CheckBoxListCreateableMediaTypes
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the default media type for creating
        /// </summary>
        protected DropDownList DropDownListDefaultMediaType
        {
            get;
            set;
        }
        #endregion

        #region Display options

        /// <summary>
        /// Gets or sets the Property Alias of an Image Cropper property
        /// </summary>
        protected TextBox TxtCropPropertyAlias
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the name of the Crop to show
        /// </summary>
        protected TextBox TxtCropName
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the height of the thumbnail preview
        /// </summary>
        protected TextBox TxtThumbnailHeight
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the width of the thumbnail preview
        /// </summary>
        protected TextBox TxtThumbnailWidth
        {
            get;
            set;
        }
        #endregion

        #region Multiple nodes

        /// <summary>
        /// Gets or sets if multiple nodes can be selected.
        /// </summary>
        protected RadioButtonList RadioSelectMultipleNodes
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets node panel.
        /// </summary>
        protected Panel PanelNode
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the minimum nodes.
        /// </summary>
        protected TextBox TxtMinimumNodes
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the maximum nodes.
        /// </summary>
        protected TextBox TxtMaximumNodes
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the minimum node start text.
        /// </summary>
        protected Literal LitMinimumNodesStart
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the minimum node end text.
        /// </summary>
        protected Literal LitMinimumNodesEnd
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the maximum node start text.
        /// </summary>
        protected Literal LitMaximumNodesStart
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the maximum node end text.
        /// </summary>
        protected Literal LitMaximumNodesEnd
        {
            get;
            set;
        }

        #endregion

        #region Buttons

        /// <summary>
        /// Gets or sets the checkbox if the edit button should be hidden.
        /// </summary>
        protected CheckBox CheckBoxHideEdit
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the checkbox if the open button should be hidden.
        /// </summary>
        protected CheckBox CheckBoxHideOpen
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the checkbox if the pixlr button should be hidden.
        /// </summary>
        protected CheckBox CheckBoxHidePixlr
        {
            get;
            set;
        }

        #endregion

        #region Search Properties

        /// <summary>
        /// Enable Search on the media picker
        /// </summary>
        public CheckBox CheckBoxEnableSearch
        {
            get;
            set;
        }

        /// <summary>
        /// Enable AutoSuggest while typing in the Search field
        /// </summary>
        public CheckBox CheckBoxEnableSearchAutoSuggest
        {
            get;
            set;
        }

        /// <summary>
        /// Search Method - either search all media or under selected node
        /// </summary>
        public RadioButtonList RadioSelectSearchMethod
        {
            get;
            set;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets the editor.
        /// </summary>
        /// <value>The editor.</value>
        public Control Editor
        {
            get
            {
                return this;
            }
        }

        #endregion

        public DAMP_PrevalueEditor(BaseDataType dataType)
        {
            this._dataType = dataType;
        }

        public void Save()
        {
            //Default save the value as a Nvarchar.
            this._dataType.DBType = DBTypes.Nvarchar;
            
            if (this.DropDownListSave.SelectedValue == "fullMedia")
            {
                //If the id and the path need to be saved, make it Ntext because it's will be stored as XML.
                this._dataType.DBType = DBTypes.Ntext;
            }

            lock (m_Locker)
            {
                var vals = GetPreValues();

                //Store the save value.
                SavePreValue(PropertyIndex.Save, this.DropDownListSave.SelectedValue, vals);

                //Store the select start node option.
                SavePreValue(PropertyIndex.SelectStartNode, this.RadioSelectStartNode.SelectedValue, vals);

                //Store the start node id.
                SavePreValue(PropertyIndex.StartNodeId, this.SimpleMediaPickerStartNode.Value, vals);

                //Store the start node xpath.
                SavePreValue(PropertyIndex.StartNodeXpath, this.TxtStartNodeXpath.Text, vals);

                //Store the ignore start node for admin value.
                SavePreValue(PropertyIndex.IgnoreStartNodeAdmin, this.CheckBoxIgnoreStartNodeAdmin.Checked.ToString(), vals);

                //Store the allowed extension.
                SavePreValue(PropertyIndex.AllowedExtension, this.TxtAllowedExtensions.Text, vals);

                //Store the allowed selectable Media Types
                SavePreValue(PropertyIndex.AllowedSelectableMediaTypes, GetCheckBoxSelections(this.CheckBoxListSelectableMediaTypes), vals);

                //Store the allowed create-able Media Types
                SavePreValue(PropertyIndex.AllowedCreateableMediaTypes, GetCheckBoxSelections(this.CheckBoxListCreateableMediaTypes), vals);

                //Store the default media type
                SavePreValue(PropertyIndex.DefaultMediaType, this.DropDownListDefaultMediaType.SelectedValue, vals);

                //Store the Create option
                SavePreValue(PropertyIndex.HideCreate, this.CheckBoxHideCreate.Checked.ToString(), vals);

                //Store if multiple nodes can be stored.
                SavePreValue(PropertyIndex.SelectMultipleNodes, this.RadioSelectMultipleNodes.SelectedValue, vals);

                //Store the minimum nodes.
                SavePreValue(PropertyIndex.MinimumNodes, this.TxtMinimumNodes.Text, vals);

                //Store the maximum nodes.
                SavePreValue(PropertyIndex.MaximumNodes, this.TxtMaximumNodes.Text, vals);

                //Store the Crop Property Alias
                SavePreValue(PropertyIndex.CropPropertyAlias, this.TxtCropPropertyAlias.Text, vals);

                //Store the Crop Name
                SavePreValue(PropertyIndex.CropName, this.TxtCropName.Text, vals);

                //Store the Thumbnail Width
                SavePreValue(PropertyIndex.ThumbnailWidth, this.TxtThumbnailWidth.Text, vals);

                //Store the Thumbnail Height
                SavePreValue(PropertyIndex.ThumbnailHeight, this.TxtThumbnailHeight.Text, vals);

                //Store the Hide Edit option
                SavePreValue(PropertyIndex.HideEdit, this.CheckBoxHideEdit.Checked.ToString(), vals);

                //Store the Hide Open option
                SavePreValue(PropertyIndex.HideOpen, this.CheckBoxHideOpen.Checked.ToString(), vals);

                //Store the Hide Pixlr option
                SavePreValue(PropertyIndex.HidePixlr, this.CheckBoxHidePixlr.Checked.ToString(), vals);

                //Store the Enable Search option
                SavePreValue(PropertyIndex.EnableSearch, this.CheckBoxEnableSearch.Checked.ToString(), vals);

                //Store the Enable Search AutoSuggest option
                SavePreValue(PropertyIndex.EnableSearchAutoSuggest, this.CheckBoxEnableSearchAutoSuggest.Checked.ToString(), vals);

                //Store the Search Method option
                SavePreValue(PropertyIndex.SearchMethod, this.RadioSelectSearchMethod.SelectedValue, vals);

            }

            //Once everything is saved, clear the cookie vals.
            DAMP_Helper.ClearCookiePersistence();
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            this.EnsureChildControls();
        }

        protected override void CreateChildControls()
        {
            base.CreateChildControls();

            #region Save

            this.DropDownListSave = new DropDownList();
            this.DropDownListSave.ID = "DdlOptions";
            this.DropDownListSave.Items.Add(new ListItem("Id", "id"));
            this.DropDownListSave.Items.Add(new ListItem("Full media xml", "fullMedia"));

            #endregion

            #region Start node

            this.MultiViewStartNode = new MultiView();
            this.MultiViewStartNode.ID = "MultiViewStartNode";

            this.ViewMediaPickerStartNode = new View();
            this.ViewMediaPickerStartNode.ID = "ViewMediaPickerStartNode";

            this.ViewXpathStartNode = new View();
            this.ViewXpathStartNode.ID = "ViewXpathStartNode";

            this.RadioSelectStartNode = new RadioButtonList();
            this.RadioSelectStartNode.ID = "RadioSelectStartNode";
            this.RadioSelectStartNode.Items.Add(new ListItem("Media Picker", "picker"));
            this.RadioSelectStartNode.Items.Add(new ListItem("XPath Expression / property alias", "xpath"));
            this.RadioSelectStartNode.RepeatDirection = RepeatDirection.Horizontal;
            this.RadioSelectStartNode.AutoPostBack = true;
            this.RadioSelectStartNode.SelectedIndexChanged += new EventHandler(RadioSelectStartNode_SelectedIndexChanged);

            this.SimpleMediaPickerStartNode = new SimpleMediaPicker();
            this.SimpleMediaPickerStartNode.ID = "SimpleMediaPickerStartNode";

            this.TxtStartNodeXpath = new TextBox();
            this.TxtStartNodeXpath.ID = "TxtStartNodeXpath";
            this.TxtStartNodeXpath.Width = new Unit(300);

            this.CheckBoxIgnoreStartNodeAdmin = new CheckBox();
            this.CheckBoxIgnoreStartNodeAdmin.ID = "CheckBoxIgnoreStartNodeAdmin";
            this.CheckBoxIgnoreStartNodeAdmin.Text = "Yes";

            this.LitPickerStart = new Literal();
            this.LitPickerStart.ID = "LitPickerStart";

            this.LitPickerEnd = new Literal();
            this.LitPickerEnd.ID = "LitPickerEnd";

            this.LitXpathStart = new Literal();
            this.LitXpathStart.ID = "LitXpathStart";

            this.LitXpathEnd = new Literal();
            this.LitXpathEnd.ID = "LitXpathEnd";

            #endregion

            #region Allowed extensions

            this.TxtAllowedExtensions = new TextBox();
            this.TxtAllowedExtensions.ID = "TxtAllowedExtenions";
            this.TxtAllowedExtensions.Width = new Unit(300);

            #endregion

            #region Media Types

            IEnumerable<MediaType> mediaTypes = MediaType.GetAllAsList();

            this.CheckBoxListSelectableMediaTypes = new CheckBoxList();
            this.CheckBoxListSelectableMediaTypes.ID = "CheckBoxListSelectableMediaTypes";
            this.CheckBoxListSelectableMediaTypes.RepeatDirection = RepeatDirection.Horizontal;
            this.CheckBoxListSelectableMediaTypes.RepeatLayout = RepeatLayout.Flow;
            // Additems
            CheckBoxListSelectableMediaTypes.DataSource = mediaTypes;
            CheckBoxListSelectableMediaTypes.DataTextField = "Text";
            CheckBoxListSelectableMediaTypes.DataValueField = "id";
            CheckBoxListSelectableMediaTypes.DataBind();

            this.CheckBoxListCreateableMediaTypes = new CheckBoxList();
            this.CheckBoxListCreateableMediaTypes.ID = "CheckBoxListCreateableMediaTypes";
            this.CheckBoxListCreateableMediaTypes.RepeatDirection = RepeatDirection.Horizontal;
            this.CheckBoxListCreateableMediaTypes.RepeatLayout = RepeatLayout.Flow;
            // Additems
            CheckBoxListCreateableMediaTypes.DataSource = mediaTypes;
            CheckBoxListCreateableMediaTypes.DataTextField = "Text";
            CheckBoxListCreateableMediaTypes.DataValueField = "id";
            CheckBoxListCreateableMediaTypes.DataBind();

            this.DropDownListDefaultMediaType = new DropDownList();
            this.DropDownListDefaultMediaType.ID = "DropDownListDefaultMediaType";

            DropDownListDefaultMediaType.DataSource = mediaTypes;
            DropDownListDefaultMediaType.DataTextField = "Text";
            DropDownListDefaultMediaType.DataValueField = "id";
            DropDownListDefaultMediaType.DataBind();

            #endregion

            #region Allow Create

            this.CheckBoxHideCreate = new CheckBox();
            this.CheckBoxHideCreate.ID = "CheckBoxHideCreate";
            this.CheckBoxHideCreate.Text = "Yes";

            #endregion

            #region Multiple nodes

            this.RadioSelectMultipleNodes = new RadioButtonList();
            this.RadioSelectMultipleNodes.ID = "RadioSelectMultipleNodes";
            this.RadioSelectMultipleNodes.Items.Add(new ListItem("Yes", "True"));
            this.RadioSelectMultipleNodes.Items.Add(new ListItem("No", "False"));
            this.RadioSelectMultipleNodes.RepeatDirection = RepeatDirection.Horizontal;
            this.RadioSelectMultipleNodes.AutoPostBack = true;
            this.RadioSelectMultipleNodes.SelectedIndexChanged += new EventHandler(SelectMultipleNodes_SelectedIndexChanged);

            this.PanelNode = new Panel();
            this.PanelNode.ID = "PanelNode";

            this.LitMinimumNodesStart = new Literal();
            this.LitMinimumNodesStart.ID = "LitMinimumNodesStart";

            this.LitMinimumNodesEnd = new Literal();
            this.LitMinimumNodesEnd.ID = "LitMinimumNodesEnd";

            this.LitMaximumNodesStart = new Literal();
            this.LitMaximumNodesStart.ID = "LitMaximumNodesStart";

            this.LitMaximumNodesEnd = new Literal();
            this.LitMaximumNodesEnd.ID = "LitMaximumNodesEnd";

            this.TxtMinimumNodes = new TextBox();
            this.TxtMinimumNodes.ID = "TxtMinimumNodes";
            this.TxtMinimumNodes.Width = new Unit(50);

            this.TxtMaximumNodes = new TextBox();
            this.TxtMaximumNodes.ID = "TxtMaximumNodes";
            this.TxtMaximumNodes.Width = new Unit(50);

            #endregion

            #region Display Options

            this.TxtCropPropertyAlias = new TextBox();
            this.TxtCropPropertyAlias.ID = "TxtCropPropertyAlias";
            this.TxtCropPropertyAlias.Width = new Unit(300);

            this.TxtCropName = new TextBox();
            this.TxtCropName.ID = "TxtCropName";
            this.TxtCropName.Width = new Unit(300);

            this.TxtThumbnailWidth = new TextBox();
            this.TxtThumbnailWidth.ID = "TxtThumbnailWidth";
            this.TxtThumbnailWidth.Width = new Unit(50);

            this.TxtThumbnailHeight = new TextBox();
            this.TxtThumbnailHeight.ID = "TxtThumbnailHeight";
            this.TxtThumbnailHeight.Width = new Unit(50);

            #endregion

            #region Buttons

            this.CheckBoxHideEdit = new CheckBox();
            this.CheckBoxHideEdit.ID = "CheckBoxHideEdit";
            this.CheckBoxHideEdit.Text = "Yes";

            this.CheckBoxHideOpen = new CheckBox();
            this.CheckBoxHideOpen.ID = "CheckBoxHideOpen";
            this.CheckBoxHideOpen.Text = "Yes";

            this.CheckBoxHidePixlr = new CheckBox();
            this.CheckBoxHidePixlr.ID = "CheckBoxHidePixlr";
            this.CheckBoxHidePixlr.Text = "Yes";

            #endregion

            #region Search

            this.CheckBoxEnableSearch = new CheckBox();
            this.CheckBoxEnableSearch.ID = "CheckBoxEnableSearch";
            this.CheckBoxEnableSearch.Text = "Yes";

            this.CheckBoxEnableSearchAutoSuggest = new CheckBox();
            this.CheckBoxEnableSearchAutoSuggest.ID = "CheckBoxEnableSearchAutoSuggest";
            this.CheckBoxEnableSearchAutoSuggest.Text = "Yes";

            this.RadioSelectSearchMethod = new RadioButtonList();
            this.RadioSelectSearchMethod.ID = "RadioSelectSearchMethod";
            this.RadioSelectSearchMethod.Items.Add(new ListItem("All media items under start node", "all"));
            this.RadioSelectSearchMethod.Items.Add(new ListItem("All media items under selected node", "selected"));

            #endregion

            #region Controls

            this.ViewMediaPickerStartNode.Controls.Add(this.LitPickerStart);
            this.ViewMediaPickerStartNode.Controls.Add(this.SimpleMediaPickerStartNode);
            this.ViewMediaPickerStartNode.Controls.Add(this.LitPickerEnd);

            this.ViewXpathStartNode.Controls.Add(this.LitXpathStart);
            this.ViewXpathStartNode.Controls.Add(this.TxtStartNodeXpath);
            this.ViewXpathStartNode.Controls.Add(this.LitXpathEnd);

            this.MultiViewStartNode.Controls.Add(this.ViewMediaPickerStartNode);
            this.MultiViewStartNode.Controls.Add(this.ViewXpathStartNode);
            
            this.PanelNode.Controls.Add(this.LitMinimumNodesStart);
            this.PanelNode.Controls.Add(this.TxtMinimumNodes);
            this.PanelNode.Controls.Add(this.LitMinimumNodesEnd);

            this.PanelNode.Controls.Add(this.LitMaximumNodesStart);
            this.PanelNode.Controls.Add(this.TxtMaximumNodes);
            this.PanelNode.Controls.Add(this.LitMaximumNodesEnd);

            this.Controls.Add(this.DropDownListSave);
            this.Controls.Add(this.RadioSelectStartNode);
            this.Controls.Add(this.MultiViewStartNode);
            this.Controls.Add(this.CheckBoxIgnoreStartNodeAdmin);
            this.Controls.Add(this.TxtAllowedExtensions);
            this.Controls.Add(this.CheckBoxListSelectableMediaTypes);
            this.Controls.Add(this.CheckBoxListCreateableMediaTypes);
            this.Controls.Add(this.DropDownListDefaultMediaType);
            this.Controls.Add(this.CheckBoxHideCreate);
            this.Controls.Add(this.RadioSelectMultipleNodes);
            this.Controls.Add(this.PanelNode);
            this.Controls.Add(this.TxtCropPropertyAlias);
            this.Controls.Add(this.TxtCropName);
            this.Controls.Add(this.TxtThumbnailWidth);
            this.Controls.Add(this.TxtThumbnailHeight);
            this.Controls.Add(this.CheckBoxHideEdit);
            this.Controls.Add(this.CheckBoxHideOpen);
            this.Controls.Add(this.CheckBoxHidePixlr);
            this.Controls.Add(this.CheckBoxEnableSearch);
            this.Controls.Add(this.CheckBoxEnableSearchAutoSuggest);
            this.Controls.Add(this.RadioSelectSearchMethod);

            #endregion
        }

        protected void RadioSelectStartNode_SelectedIndexChanged(object sender, EventArgs e)
        {
            //Show the view with the Media Picker or the XPath textbox.
            this.MultiViewStartNode.SetActiveView(((RadioButtonList)sender).SelectedValue == "picker" ? this.ViewMediaPickerStartNode : this.ViewXpathStartNode);
        }

        protected void SelectMultipleNodes_SelectedIndexChanged(object sender, EventArgs e)
        {
            //Show/Hide the minimum and minimum node selection.
            this.PanelNode.Visible = Convert.ToBoolean(((RadioButtonList)sender).SelectedValue);
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            if (!this.Page.IsPostBack)
            {
                this.DropDownListSave.SelectedValue = SaveValue;
                this.RadioSelectStartNode.SelectedValue = SelectStartPickerValue;
                this.SimpleMediaPickerStartNode.Value = StartNodeIdValue.ToString();
                this.TxtStartNodeXpath.Text = StartNodeXpathValue;
                this.MultiViewStartNode.SetActiveView(this.RadioSelectStartNode.SelectedValue == "picker" ? this.ViewMediaPickerStartNode : this.ViewXpathStartNode);
                this.CheckBoxIgnoreStartNodeAdmin.Checked = IgnoreStartNodeAdminValue;
                this.TxtAllowedExtensions.Text = AllowedExtensionValue;
                SetCheckBoxSelections(this.CheckBoxListSelectableMediaTypes, AllowedSelectableMediaTypesValue);
                SetCheckBoxSelections(this.CheckBoxListCreateableMediaTypes, AllowedCreateableMediaTypesValue);
                this.DropDownListDefaultMediaType.SelectedValue = DefaultMediaTypeValue.ToString(); // CP TD** //
                this.CheckBoxHideCreate.Checked = HideCreateValue;
                this.RadioSelectMultipleNodes.SelectedValue = SelectMultipleNodesValue.ToString();
                this.TxtMinimumNodes.Text = MinimumNodesValue.ToString();
                this.TxtMaximumNodes.Text = MaximumNodesValue.ToString();
                this.PanelNode.Visible = Convert.ToBoolean(this.RadioSelectMultipleNodes.SelectedValue);
                this.TxtCropPropertyAlias.Text = CropPropertyAliasValue;
                this.TxtCropName.Text = CropNameValue;
                this.TxtThumbnailWidth.Text = ThumbnailWidthValue.ToString();
                this.TxtThumbnailHeight.Text = ThumbnailHeightValue.ToString();
                this.CheckBoxHideEdit.Checked = HideEditValue;
                this.CheckBoxHideOpen.Checked = HideOpenValue;
                this.CheckBoxHidePixlr.Checked = HidePixlrValue;
                this.CheckBoxEnableSearch.Checked = EnableSearch;
                this.CheckBoxEnableSearchAutoSuggest.Checked = EnableSearchAutoSuggest;
                this.RadioSelectSearchMethod.SelectedValue = SearchMethod;
            }

            this.LitPickerStart.Text = "<tr><th>Start node Media Picker:</th><td style=\"padding-bottom: 20px;\"><div>";
            this.LitPickerEnd.Text = "</div><div style=\"color: #666; font-style: italic; margin-top: 5px;\">Define the starting node by picker that should be rendered for the media picker. This will ensure that the correct security measures are in place by checking the defined start node for the user accessing the media picker. In some cases, if the user is not able to view the node, then the media picker will render an error message.</div></td></tr>";

            this.LitXpathStart.Text = "<tr><th>Start node XPath / property alias:</th><td><div>";
            this.LitXpathEnd.Text = "</div><div style=\"color: #666; font-style: italic; margin-top: 5px;\">This field will first check if a property alias with the filled in value exists on the current node. If it does the value from that property will be used as a start node.<br /><br />Define the starting node by XPath that should be rendered for the media picker. This will ensure that the correct security measures are in place by checking the defined start node for the user accessing the media picker. The first found node will be used. If the XPath doesn't find a node the user will see the complete media tree which he has rights to. There is no currentPage available. Sample: \"/descendant::Folder[@nodeName='HeaderImages']\"</div></td></tr>";

            this.LitMinimumNodesStart.Text = "<tr><th>Minimum nodes:</th><td style=\"padding-bottom: 20px;\"><div>";
            this.LitMinimumNodesEnd.Text = "</div><div style=\"color: #666; font-style: italic; margin-top: 5px;\">The minimum number of media items that are allowed to be selected by a user. To ignore this check enter -1 as the value.</div></td></tr>";

            this.LitMaximumNodesStart.Text = "<tr><th>Maximum nodes:</th><td><div>";
            this.LitMaximumNodesEnd.Text = "</div><div style=\"color: #666; font-style: italic; margin-top: 5px;\">The maximum number of media items that are allowed to be selected by a user. To ignore this check enter -1 as the value.</div></td></tr>";
        }

        protected override void Render(HtmlTextWriter writer)
        {
            writer.AddAttribute(HtmlTextWriterAttribute.Style, "background: transparent url(" + IOHelper.ResolveUrl(SystemDirectories.Umbraco) + "/plugins/DigibizAdvancedMediaPicker/Logo.png) no-repeat right 8px; padding-top: 40px;");

            writer.RenderBeginTag(HtmlTextWriterTag.Div);

            writer.WriteLine("<table>");

            writer.Write("<tr><th>Store:</th><td style=\"padding-bottom: 20px;\"><div>");
            this.DropDownListSave.RenderControl(writer);
            writer.Write("</div><div style=\"color: #666; font-style: italic; margin-top: 5px;\">Only store the id like the normal media picker or the full media xml. With the full media xml you don't need to use umbraco.library:GetMedia in XSLT. If you update/delete a media item in the media section, the full media xml will be updated automatically using events.</div></td></tr>");

            writer.Write("<tr><th>Start Node Options:</th><td style=\"padding-bottom: 20px;\"><div class=\"propertypane\">");
            writer.Write("<table>");

            writer.Write("<tr><th>Start node selection:</th><td style=\"padding-bottom: 20px;\"><div>");
            this.RadioSelectStartNode.RenderControl(writer);
            writer.Write("</div><div style=\"color: #666; font-style: italic; margin-top: 5px;\">The start node can be selected from a parent node (Media Picker) or by an XPath Expression / property alias.</div></td></tr>");

            this.MultiViewStartNode.RenderControl(writer);

            writer.Write("<tr><th>Ignore start node for admin:</th><td style=\"padding-bottom: 20px;\"><div>");
            this.CheckBoxIgnoreStartNodeAdmin.RenderControl(writer);
            writer.Write("</div><div style=\"color: #666; font-style: italic; margin-top: 5px;\">If the checkbox is checked no start node will be used for the admin. This way the admin can always see the complete media tree he has rights to.</div></td></tr>");

            writer.Write("</table></div></td></tr>");

            writer.Write("<tr><th>Restrictions:</th><td style=\"padding-bottom: 20px;\"><div class=\"propertypane\">");
            writer.Write("<table>");

            writer.Write("<tr><th>Allowed extensions:</th><td style=\"padding-bottom: 20px;\"><div>");
            this.TxtAllowedExtensions.RenderControl(writer);
            writer.Write("</div><div style=\"color: #666; font-style: italic; margin-top: 5px;\">Make a comma seperated list of allowed extensions. For example: \"jpg,gif,png\". To ignore this check leave it empty or enter \"all\" as the value.</div></td></tr>");

            writer.Write("<tr><th>Allowed Media Types:</th><td style=\"padding-bottom: 20px;\"><div>");
            writer.Write("<table><tr><td><strong>Selectable</strong></td><td>");
            this.CheckBoxListSelectableMediaTypes.RenderControl(writer);
            writer.Write("</td></tr><tr><td><strong>Create-able</strong></td><td>");
            this.CheckBoxListCreateableMediaTypes.RenderControl(writer);
            writer.Write("</td></tr></table>");
            writer.Write("</div><div style=\"color: #666; font-style: italic; margin-top: 5px;\">Select Media Types that are allowed to be created & selected.  Leave blank to allow any media type.</div></td></tr>");

            writer.Write("<tr><th>Default media type:</th><td style=\"padding-bottom: 20px;\"><div>");
            this.DropDownListDefaultMediaType.RenderControl(writer);
            writer.Write("</div><div style=\"color: #666; font-style: italic; margin-top: 5px;\">Optionally select a Default Media Type to select when the user Creates a new media.</div></td></tr>");

            writer.Write("</table></div></td></tr>");

            writer.Write("<tr><th>Multiple Media Options:</th><td style=\"padding-bottom: 20px;\"><div class=\"propertypane\">");
            writer.Write("<table>");

            writer.Write("<tr><th>Select multiple media items:</th><td style=\"padding-bottom: 20px;\"><div>");
            this.RadioSelectMultipleNodes.RenderControl(writer);
            writer.Write("</div><div style=\"color: #666; font-style: italic; margin-top: 5px;\">Choose if only a single media item can be selected like the normal media picker or if multiple media items can be selected in the same media picker.</div></td></tr>");

            this.PanelNode.RenderControl(writer);

            writer.Write("</table></div></td></tr>");

            writer.Write("<tr><th>Display Options:</th><td style=\"padding-bottom: 20px;\"><div class=\"propertypane\">");
            writer.Write("<table>");

            writer.Write("<tr><th>Thumbnail Width / Height:</th><td style=\"padding-bottom: 20px;\"><div>");
            this.TxtThumbnailWidth.RenderControl(writer);
            writer.Write(" x ");
            this.TxtThumbnailHeight.RenderControl(writer);
            writer.Write("</div><div style=\"color: #666; font-style: italic; margin-top: 5px;\">Desired width/height (pixels) of thumbnails to display in backend UI.  Set either value to 0 to resize by one dimension. Thumbnails in the select or create dialog never have a bigger width/height than a 100 pixels.</div></td></tr>");

            writer.Write("<tr><th>Image Cropper Property Alias:</th><td style=\"padding-bottom: 20px;\"><div>");
            this.TxtCropPropertyAlias.RenderControl(writer);
            writer.Write("</div><div style=\"color: #666; font-style: italic; margin-top: 5px;\">Optionally specify the Alias of an Image Cropper property.  If a crop is found, it will be shown in the preview instead of the standard thumbnail.</div></td></tr>");

            writer.Write("<tr><th>Image Cropper Crop Name:</th><td style=\"padding-bottom: 20px;\"><div>");
            this.TxtCropName.RenderControl(writer);
            writer.Write("</div><div style=\"color: #666; font-style: italic; margin-top: 5px;\">Name of configured Crop to use.  Leave blank to use the first found.</div></td></tr>");

            writer.Write("</table></div></td></tr>");

            writer.Write("<tr><th>Search:</th><td style=\"padding-bottom: 20px;\"><div class=\"propertypane\">");
            writer.Write("<table>");

            writer.Write("<tr><th style=\"width: 114px;\">Enable:</th><td style=\"padding-bottom: 20px;\"><div>");
            this.CheckBoxEnableSearch.RenderControl(writer);
            writer.Write("</div><div style=\"color: #666; font-style: italic; margin-top: 5px;\">This will display a Search bar in the Media Picker and allow users to search through available media item.</div></td></tr>");

            writer.Write("<tr><th style=\"width: 114px;\">Enable AutoSuggest:</th><td style=\"padding-bottom: 20px;\"><div>");
            this.CheckBoxEnableSearchAutoSuggest.RenderControl(writer);
            writer.Write("</div><div style=\"color: #666; font-style: italic; margin-top: 5px;\">This will enable AutoSuggesting available media items when typing in the search field.</div></td></tr>");

            writer.Write("<tr><th style=\"width: 114px;\">Search Method:</th><td style=\"padding-bottom: 20px;\"><div>");
            this.RadioSelectSearchMethod.RenderControl(writer);
            writer.Write("</div><div style=\"color: #666; font-style: italic; margin-top: 5px;\">This will tell the media picker to either search through all media items or under the current selected node from the left media tree.</div></td></tr>");

            writer.Write("</table></div></td></tr>");

            writer.Write("<tr><th>Buttons:</th><td style=\"padding-bottom: 20px;\"><div class=\"propertypane\">");
            writer.Write("<table>");

            writer.Write("<tr><th style=\"width: 114px;\">Hide Create button:</th><td style=\"padding-bottom: 20px;\"><div>");
            this.CheckBoxHideCreate.RenderControl(writer);
            writer.Write("</div><div style=\"color: #666; font-style: italic; margin-top: 5px;\">The Create button will be on by default, but can be disabled by checking this checkbox.</div></td></tr>");

            writer.Write("<tr><th style=\"width: 114px;\">Hide Edit button:</th><td style=\"padding-bottom: 20px;\"><div>");
            this.CheckBoxHideEdit.RenderControl(writer);
            writer.Write("</div><div style=\"color: #666; font-style: italic; margin-top: 5px;\">The Edit button will be on by default, but can be disabled by checking this checkbox.</div></td></tr>");

            writer.Write("<tr><th style=\"width: 114px;\">Hide Open button:</th><td style=\"padding-bottom: 20px;\"><div>");
            this.CheckBoxHideOpen.RenderControl(writer);
            writer.Write("</div><div style=\"color: #666; font-style: italic; margin-top: 5px;\">The Open button will be on by default, but can be disabled by checking this checkbox.</div></td></tr>");

            writer.Write("<tr><th style=\"width: 114px;\">Hide Pixlr button:</th><td style=\"padding-bottom: 20px;\"><div>");
            this.CheckBoxHidePixlr.RenderControl(writer);
            writer.Write("</div><div style=\"color: #666; font-style: italic; margin-top: 5px;\">The Pixlr button will be on by default, but can be disabled by checking this checkbox.</div></td></tr>");

            writer.Write("</table></div></td></tr>");

            writer.Write("</table>");

            writer.RenderEndTag();
        }

        /// <summary>
        /// Used to determine the index number of where the property is saved in the pre values repository.
        /// The numbered order is a bit strange, but we need it in this order for compatibility with older versions of the package.
        /// </summary>
        public enum PropertyIndex
        {
            Save = 0,
            StartNodeId = 1,
            AllowedExtension = 2,
            SelectMultipleNodes = 3,
            MinimumNodes = 4,
            MaximumNodes = 5,
            SelectStartNode = 6,
            StartNodeXpath = 7,
            IgnoreStartNodeAdmin = 8,
            HideCreate = 9,
            AllowedSelectableMediaTypes = 10,
            AllowedCreateableMediaTypes = 11,
            DefaultMediaType = 12,
            ThumbnailWidth = 13,
            ThumbnailHeight = 14,
            CropPropertyAlias = 15,
            CropName = 16,
            HideEdit = 17,
            HideOpen = 18,
            HidePixlr = 19,
            EnableSearch = 20,
            EnableSearchAutoSuggest = 21,
            SearchMethod = 22
        }

        #region Public properties
        
        public string SaveValue
        {
            get
            {
                return GetPreValue(PropertyIndex.Save, x => x.Value, "id");
            }
        }

        public string SelectStartPickerValue
        {
            get
            {
                return GetPreValue(PropertyIndex.SelectStartNode, x =>
                {
                    return x.Value;
                }, "picker");
            }
        }
        
        public int StartNodeIdValue
        {
            get
            {
                return GetPreValue(PropertyIndex.StartNodeId, x =>
                {
                    var startNode = -1;
                    return int.TryParse(x.Value, out startNode) ? startNode : -1;
                }, -1);
            }
        }

        public string StartNodeXpathValue
        {
            get
            {
                return GetPreValue(PropertyIndex.StartNodeXpath, x => x.Value, DigibizConstants.DEFAULTSTARTNODEXPATH);
            }
        }

        public bool IgnoreStartNodeAdminValue
        {
            get
            {
                return GetPreValue(PropertyIndex.IgnoreStartNodeAdmin, x =>
                {
                    var yes = false;
                    return bool.TryParse(x.Value, out yes) ? yes : false;
                }, false);
            }
        }

        public string AllowedExtensionValue
        {
            get
            {
                return GetPreValue(PropertyIndex.AllowedExtension, x => x.Value, DigibizConstants.ALLEXTENSIONS);
            }
        }

        public string AllowedSelectableMediaTypesValue
        {
            get
            {
                return GetPreValue(PropertyIndex.AllowedSelectableMediaTypes, x => x.Value, string.Empty);
            }
        }

        public string AllowedCreateableMediaTypesValue
        {
            get
            {
                return GetPreValue(PropertyIndex.AllowedCreateableMediaTypes, x => x.Value, string.Empty);
            }
        }

        public int DefaultMediaTypeValue
        {
            get
            {
                return GetPreValue(PropertyIndex.DefaultMediaType, x =>
                {
                    var def = 0;
                    return int.TryParse(x.Value, out def) ? def : 0;
                }, 0);
            }
        }

        public bool HideCreateValue
        {
            get
            {
                return GetPreValue(PropertyIndex.HideCreate, x =>
                {
                    var yes = false;
                    return bool.TryParse(x.Value, out yes) ? yes : false;
                }, false);
            }
        }
        public bool SelectMultipleNodesValue
        {
            get
            {
                return GetPreValue(PropertyIndex.SelectMultipleNodes, x =>
                {
                    var selectMultiple = true;
                    return bool.TryParse(x.Value, out selectMultiple) ? selectMultiple : true;
                }, true);
            }
        }

        public int MinimumNodesValue
        {
            get
            {
                return GetPreValue(PropertyIndex.MinimumNodes, x =>
                {
                    var min = -1;
                    return int.TryParse(x.Value, out min) ? min : -1;
                }, -1);
            }
        }

        public int MaximumNodesValue
        {
            get
            {
                return GetPreValue(PropertyIndex.MaximumNodes, x =>
                {
                    var max = -1;
                    return int.TryParse(x.Value, out max) ? max : -1;
                }, -1);
            }
        }

        public string CropPropertyAliasValue
        {
            get
            {
                return GetPreValue(PropertyIndex.CropPropertyAlias, x => x.Value, string.Empty);
            }
        }

        public string CropNameValue
        {
            get
            {
                return GetPreValue(PropertyIndex.CropName, x => x.Value, string.Empty);
            }
        }

        public int ThumbnailWidthValue
        {
            get
            {
                return GetPreValue(PropertyIndex.ThumbnailWidth, x =>
                {
                    var max = 50;
                    return int.TryParse(x.Value, out max) ? max : 100;
                }, 100);
            }
        }

        public int ThumbnailHeightValue
        {
            get
            {
                return GetPreValue(PropertyIndex.ThumbnailHeight, x =>
                {
                    var max = 50;
                    return int.TryParse(x.Value, out max) ? max : 100;
                }, 100);
            }
        }

        public bool HideEditValue
        {
            get
            {
                return GetPreValue(PropertyIndex.HideEdit, x =>
                {
                    var yes = false;
                    return bool.TryParse(x.Value, out yes) ? yes : false;
                }, false);
            }
        }

        public bool HideOpenValue
        {
            get
            {
                return GetPreValue(PropertyIndex.HideOpen, x =>
                {
                    var yes = false;
                    return bool.TryParse(x.Value, out yes) ? yes : false;
                }, false);
            }
        }

        public bool HidePixlrValue
        {
            get
            {
                return GetPreValue(PropertyIndex.HidePixlr, x =>
                {
                    var yes = false;
                    return bool.TryParse(x.Value, out yes) ? yes : false;
                }, false);
            }
        }

        public bool EnableSearch
        {
            get
            {
                return GetPreValue(PropertyIndex.EnableSearch, x =>
                {
                    var yes = false;
                    return bool.TryParse(x.Value, out yes) ? yes : false;
                }, true);
            }
        }

        public bool EnableSearchAutoSuggest
        {
            get
            {
                return GetPreValue(PropertyIndex.EnableSearchAutoSuggest, x =>
                {
                    var yes = false;
                    return bool.TryParse(x.Value, out yes) ? yes : false;
                }, true);
            }
        }

        public string SearchMethod
        {
            get
            {
                return GetPreValue(PropertyIndex.SearchMethod, x => x.Value, "all");
            }
        }

        #endregion

        /// <summary>
        /// Lazy loads the prevalues for this data type.
        /// </summary>
        /// <returns></returns>
        public SortedList GetPreValues()
        {
            if (this._preValues == null)
            {
                this._preValues = PreValues.GetPreValues(this._dataType.DataTypeDefinitionId);
            }
            return this._preValues;
        }

        /// <summary>
        /// Helper method to save/create pre value values in the db.
        /// </summary>
        /// <param name="propIndex"></param>
        /// <param name="value"></param>
        /// <param name="currentVals"></param>
        public void SavePreValue(PropertyIndex propIndex, string value, SortedList currentVals)
        {
            var index = (int)propIndex;
            if (currentVals.Count >= (index + 1))
            {
                //Update.
                ((PreValue)currentVals[index]).Value = value;
                ((PreValue)currentVals[index]).SortOrder = index + 1; // See comment below (Insert).  Adding this here also to migrate existing prevalues (from devs using changesets) to match the 'sortorder' format
                ((PreValue)currentVals[index]).Save();
            }
            else
            {
                //Insert.
                PreValue pv = PreValue.MakeNew(this._dataType.DataTypeDefinitionId, value);
                pv.SortOrder = index + 1;   // We need to set the sortorder when adding new prevalues, otherwise SortOrder is set to 0 and causes them to return first, invalidating the propertyindex
                pv.Save();

            }
        }

        ///<summary>
        /// Generic method to return a strongly typed object from the pre value bucket.
        ///</summary>
        ///<param name="index"></param>
        ///<param name="output"></param>
        ///<param name="defaultVal"></param>
        ///<typeparam name="T"></typeparam>
        ///<returns></returns>
        private T GetPreValue<T>(PropertyIndex propIndex, Func<PreValue, T> output, T defaultVal)
        {
            var index = (int)propIndex;

            var vals = GetPreValues();
            return vals.Count >= index + 1 ? output((PreValue)vals[index]) : defaultVal;
        }

        /// <summary>
        /// Helper method to return a comma-separated list of selected items in a CheckBoxList.  Needed as .SelectedValue only returns one item.
        /// </summary>
        /// <param name="cbl"></param>
        /// <returns></returns>
        private string GetCheckBoxSelections(CheckBoxList cbl)
        {
            string selectedValues = string.Empty;

            foreach (ListItem li in cbl.Items)
            {
                if (li.Selected)
                {
                    selectedValues += li.Value + ",";
                }
            }
            
            selectedValues = selectedValues.TrimEnd(',');

            return selectedValues;
        }

        /// <summary>
        /// Helper method to set selected items in a CheckBoxList from a comma-separated string.
        /// </summary>
        /// <param name="cbl"></param>
        /// <param name="selectedValues"></param>
        private void SetCheckBoxSelections(CheckBoxList cbl, string selectedValues)
        {
            if (!selectedValues.StartsWith(",")) 
            {
                selectedValues = "," + selectedValues;
            }
            if (!selectedValues.EndsWith(",")) 
            {
                selectedValues = selectedValues + ",";
            }

            foreach (ListItem li in cbl.Items)
            {
                if (!(selectedValues.IndexOf("," + li.Value + ",") < 0))
                {
                    li.Selected = true;
                }
            }
        }
    }
}